package com.hmy.finance.job.core;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hmy.finance.api.bo.core.request.enums.FeeTypeEnum;
import com.hmy.finance.common.constants.CommonConstants;
import com.hmy.finance.common.enums.BusinessBillTypeEnum;
import com.hmy.finance.common.enums.ProfitLossStatusEnum;
import com.hmy.finance.common.properties.ReceivableInventoryOverdueRule;
import com.hmy.finance.dal.mapper.ReceivableInventoryMapper;
import com.hmy.finance.dal.po.*;
import com.hmy.finance.dal.po.json.OverdueDetailJson;
import com.hmy.finance.service.core.*;
import com.hmy.finance.service.core.dto.DailyInvoiceGenerationJobDto;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Component
public class NullifyDeviceDailyFeeBillHandler {
    private final IDeviceRentalRecordService deviceRentalRecordService;
    private final IDeviceDailyBillService deviceDailyBillService;
    private final IContractDailyBillService contractDailyBillService;
    private final IDeviceProfitLossDetailService deviceProfitLossDetailService;
    private final IProfitLossRecordService profitLossRecordService;

    private final ReceivableInventoryMapper receivableInventoryMapper;

    public NullifyDeviceDailyFeeBillHandler(IDeviceRentalRecordService deviceRentalRecordService, IDeviceDailyBillService deviceDailyBillService, IContractDailyBillService contractDailyBillService, IDeviceProfitLossDetailService deviceProfitLossDetailService, IProfitLossRecordService profitLossRecordService, ReceivableInventoryMapper receivableInventoryMapper) {
        this.deviceRentalRecordService = deviceRentalRecordService;
        this.deviceDailyBillService = deviceDailyBillService;
        this.contractDailyBillService = contractDailyBillService;
        this.deviceProfitLossDetailService = deviceProfitLossDetailService;
        this.profitLossRecordService = profitLossRecordService;
        this.receivableInventoryMapper = receivableInventoryMapper;
    }

    @XxlJob("financial_nullifyDailyInvoiceBill")
    @Transactional(rollbackFor = Exception.class)
    public void execute(String s) {
        String param = XxlJobHelper.getJobParam();
        String[] args = param.split(",");
        log.info("NullifyDeviceDailyFeeBillHandler execute.Args:{}", (Object[]) args);
        String contractId = args[0];
        String startDate = null;
        String endDate = null;
        if (args.length == 3) {
            startDate = args[1];
            endDate = args[2];
        }


        if (Objects.isNull(startDate)) {
            startDate = LocalDate.now().toString();
        }
        if (Objects.isNull(endDate)) {
            endDate = LocalDate.now().toString();
        }
        List<Long> waitSetWaitEffectiveDeviceProfitLossList = new ArrayList<>();
        List<Long> waitSetWaitEffectiveContractProfitLossList = new ArrayList<>();
        log.info("NullifyDeviceDailyFeeBillHandler execute,contractId:{},startDate:{},endDate:{}", contractId, startDate, endDate);
        LambdaQueryWrapper<DeviceDailyBillPo> deviceDailyBillPoLambdaQueryWrapper = Wrappers.lambdaQuery(DeviceDailyBillPo.class);
        LambdaQueryWrapper<ContractDailyBillPo> contractDailyBillPoLambdaQueryWrapper = Wrappers.lambdaQuery(ContractDailyBillPo.class);
        deviceDailyBillPoLambdaQueryWrapper.eq(DeviceDailyBillPo::getFeeStatus, true);
        if (contractId != null) {
            deviceDailyBillPoLambdaQueryWrapper.eq(DeviceDailyBillPo::getContractId, contractId);
            contractDailyBillPoLambdaQueryWrapper.eq(ContractDailyBillPo::getContractId, contractId);

        }
        if (startDate != null) {
            deviceDailyBillPoLambdaQueryWrapper.ge(DeviceDailyBillPo::getFeeIncurredTime, LocalDate.parse(startDate).atStartOfDay());
            contractDailyBillPoLambdaQueryWrapper.ge(ContractDailyBillPo::getFeeIncurredTime, LocalDate.parse(startDate).atStartOfDay());

        }
        if (endDate != null) {
            deviceDailyBillPoLambdaQueryWrapper.le(DeviceDailyBillPo::getFeeIncurredTime, LocalDate.parse(endDate).atTime(LocalTime.MAX));
            contractDailyBillPoLambdaQueryWrapper.le(ContractDailyBillPo::getFeeIncurredTime, LocalDate.parse(endDate).atTime(LocalTime.MAX));

        }

        List<DeviceDailyBillPo> deviceDailyBillPoList = deviceDailyBillService.list(deviceDailyBillPoLambdaQueryWrapper);
        List<ContractDailyBillPo> contractDailyBillPoList = contractDailyBillService.list(contractDailyBillPoLambdaQueryWrapper);
        deviceDailyBillPoList.forEach(deviceDailyBillPo -> {
            deviceDailyBillPo.getProfitLossInfo().forEach(profitLossInfo -> {
                waitSetWaitEffectiveDeviceProfitLossList.add(profitLossInfo.getDetailId());
            });
        });
        contractDailyBillPoList.forEach(contractDailyBillPo -> {
            contractDailyBillPo.getProfitLossInfo().forEach(profitLossInfo -> {
                waitSetWaitEffectiveContractProfitLossList.add(profitLossInfo.getDetailId());
            });
        });
        Boolean updateContractFeeStatusResult = contractDailyBillService.removeByIds(contractDailyBillPoList.stream().map(ContractDailyBillPo::getId).collect(Collectors.toList()));
        log.info("NullifyDeviceDailyFeeBillHandler execute,updateContractFeeStatusResult:{}", updateContractFeeStatusResult);
        DeviceDailyBillPo updatePo = new DeviceDailyBillPo();
        updatePo.setFeeStatus(false);
        Boolean updateFeeStatusResult = deviceDailyBillService.update(updatePo, deviceDailyBillPoLambdaQueryWrapper);
        log.info("NullifyDeviceDailyFeeBillHandler execute,updateFeeStatusResult:{}", updateFeeStatusResult);
        if (!waitSetWaitEffectiveDeviceProfitLossList.isEmpty()) {
            DeviceProfitLossDetailPo deviceProfitLossDetailPo = new DeviceProfitLossDetailPo();
            deviceProfitLossDetailPo.setStatus(ProfitLossStatusEnum.WAIT_EFFECTIVE);
            deviceProfitLossDetailService.update(deviceProfitLossDetailPo, Wrappers.lambdaQuery(DeviceProfitLossDetailPo.class).in(DeviceProfitLossDetailPo::getId, waitSetWaitEffectiveDeviceProfitLossList));
        }
        if (!waitSetWaitEffectiveContractProfitLossList.isEmpty()) {
            ProfitLossRecordPo profitLossRecordPo = new ProfitLossRecordPo();
            profitLossRecordPo.setStatus(ProfitLossStatusEnum.WAIT_EFFECTIVE);
            profitLossRecordService.update(profitLossRecordPo, Wrappers.lambdaQuery(ProfitLossRecordPo.class).in(ProfitLossRecordPo::getId, waitSetWaitEffectiveContractProfitLossList));
        }
        List<DeviceRentalRecordPo> rentingRecordList = deviceRentalRecordService.list(Wrappers.lambdaQuery(DeviceRentalRecordPo.class).eq(DeviceRentalRecordPo::getContractId, contractId));
        List<DeviceRentalRecordPo> waitUpdateDeviceRentalRecordList = new ArrayList<>();
        rentingRecordList.forEach(deviceRentalRecordPo -> {
            Stream<DeviceDailyBillPo> deviceDailyBillPoStream = deviceDailyBillPoList.stream().filter(deviceDailyBillPo -> deviceDailyBillPo.getDeviceId().equals(deviceRentalRecordPo.getDeviceId()));
//            if (deviceDailyBillPoStream.findAny().isEmpty()) {
//                return;
//            }
            Double chargeDays = deviceDailyBillPoList.stream().filter(deviceDailyBillPo -> deviceDailyBillPo.getDeviceId().equals(deviceRentalRecordPo.getDeviceId())).map(DeviceDailyBillPo::getChargeDays).mapToDouble(Double::doubleValue).sum();
            deviceRentalRecordPo.setTotalRentalDays(deviceRentalRecordPo.getTotalRentalDays() - chargeDays);
            BigDecimal subAmount = deviceDailyBillPoList.stream().filter(deviceDailyBillPo -> deviceDailyBillPo.getDeviceId().equals(deviceRentalRecordPo.getDeviceId())).map(DeviceDailyBillPo::getFee).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal subtract = deviceRentalRecordPo.getTotalRentalAmount().subtract(subAmount);
            BigDecimal profitAmount = deviceDailyBillPoList.stream().filter(deviceDailyBillPo -> deviceDailyBillPo.getDeviceId().equals(deviceRentalRecordPo.getDeviceId())).map(DeviceDailyBillPo::getTotalProfitLossAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            deviceRentalRecordPo.setTotalProfitLossAmount(deviceRentalRecordPo.getTotalProfitLossAmount().subtract(profitAmount));
            deviceRentalRecordPo.setTotalRentalAmount(subtract.compareTo(BigDecimal.ZERO) > 0 ? subtract : BigDecimal.ZERO);
            deviceRentalRecordPo.setTotalRevenueAmount(deviceRentalRecordPo.getTotalRentalAmount().add(deviceRentalRecordPo.getTotalProfitLossAmount()));
            if (deviceRentalRecordPo.getTotalRentalAmount().compareTo(deviceRentalRecordPo.getMonthlyRentalPrice()) < 0) {
                deviceRentalRecordPo.setUseMonthlyRentalPrice(false);
            }
            waitUpdateDeviceRentalRecordList.add(deviceRentalRecordPo);
        });
        deviceRentalRecordService.updateBatchById(waitUpdateDeviceRentalRecordList);

        //事务提交后执行
        String finalStartDate = startDate;
        rentingRecordList.forEach(deviceRentalRecordPo -> {
            if (deviceRentalRecordPo.getExpenseCycleEndTime() != null && deviceRentalRecordPo.getExpenseCycleEndTime().isBefore(LocalDate.parse(finalStartDate).atStartOfDay())) {
                return;
            }
            int gracePeriod = deviceRentalRecordPo.getOrderExtensionInfo().getAccountPeriodDays();
            if (deviceRentalRecordPo.getOrderExtensionInfo().getAccountPeriod().equals(1)) {
                gracePeriod = 5;
            }
            Map<String, DailyInvoiceGenerationJobDto.PeriodInterval> accountPeriodIntervalMap = new HashMap<>();

            LocalDate unexpiredPeriodStart;
            LocalDate unexpiredPeriodEnd;
            LocalDate prevPeriodStart;
            LocalDate prevPeriodEnd;
            LocalDate firstOverdueStart;
            LocalDate firstOverdueEnd;
            LocalDate secondOverdueStart;
            LocalDate secondOverdueEnd;
            LocalDate thirdOverdueStart;
            LocalDate thirdOverdueEnd;
            LocalDate fourthOverdueStart;
            LocalDate fourthOverdueEnd;
            if (deviceRentalRecordPo.getOrderExtensionInfo().getSettlementMethod().equals(10)) {
                //如果是月结
                unexpiredPeriodStart = LocalDate.now().withDayOfMonth(1);
                //如果unexpiredPeriodStart在rentalRecordPo的rentalStartDate之前，则unexpiredPeriodStart设置为rentalRecordPo的rentalStartDate的00:00:00
                if (unexpiredPeriodStart.isBefore(deviceRentalRecordPo.getRentalStartTime().toLocalDate())) {
                    unexpiredPeriodStart = deviceRentalRecordPo.getRentalStartTime().toLocalDate();
                }
                unexpiredPeriodEnd = LocalDate.now().withDayOfMonth(unexpiredPeriodStart.lengthOfMonth());
                //如果当前时间处于当前月1号-当前月1号+宽限期，则上个月的账期为当前账期，否则为逾期0-30天
                prevPeriodStart = LocalDate.now().minusMonths(1).withDayOfMonth(1);
                prevPeriodEnd = prevPeriodStart.withDayOfMonth(prevPeriodStart.lengthOfMonth());
                firstOverdueStart = prevPeriodStart.minusMonths(1).withDayOfMonth(1);
                firstOverdueEnd = firstOverdueStart.withDayOfMonth(firstOverdueStart.lengthOfMonth());
                secondOverdueStart = firstOverdueStart.minusMonths(1).withDayOfMonth(1);
                secondOverdueEnd = secondOverdueStart.withDayOfMonth(secondOverdueStart.lengthOfMonth());
                thirdOverdueStart = secondOverdueStart.minusMonths(1).withDayOfMonth(1);
                thirdOverdueEnd = thirdOverdueStart.withDayOfMonth(thirdOverdueStart.lengthOfMonth());
                fourthOverdueStart = thirdOverdueStart.minusMonths(1).withDayOfMonth(1);
                fourthOverdueEnd = fourthOverdueStart.withDayOfMonth(fourthOverdueStart.lengthOfMonth());
            } else {
                //如果是期结
                //计算当前日期与起租时间之间的账期差,30个自然日为一个账期
                // 设定账期的天数
                int daysPerBillingCycle = 30;
                //计算当前日期与起租时间之间的自然日差
                // 计算自然日差
                long daysDiff = ChronoUnit.DAYS.between(deviceRentalRecordPo.getRentalStartTime().toLocalDate(), LocalDate.now());
                // 计算账期余数
                long remainder = daysDiff % daysPerBillingCycle;
                //今日所属账期开始时间为：当前时间往前推remainder天
                unexpiredPeriodStart = LocalDate.now().minusDays(remainder);
                //今日所属账期结束时间为：当前时间往前推remainder天+30天
                unexpiredPeriodEnd = unexpiredPeriodStart.plusDays(daysPerBillingCycle - 1);
                prevPeriodStart = unexpiredPeriodStart.minusDays(daysPerBillingCycle);
                prevPeriodEnd = prevPeriodStart.plusDays(daysPerBillingCycle - 1);
                firstOverdueStart = prevPeriodStart.minusDays(daysPerBillingCycle);
                firstOverdueEnd = firstOverdueStart.plusDays(daysPerBillingCycle - 1);
                secondOverdueStart = firstOverdueStart.minusDays(daysPerBillingCycle);
                secondOverdueEnd = secondOverdueStart.plusDays(daysPerBillingCycle - 1);
                thirdOverdueStart = secondOverdueStart.minusDays(daysPerBillingCycle);
                thirdOverdueEnd = thirdOverdueStart.plusDays(daysPerBillingCycle - 1);
                fourthOverdueStart = thirdOverdueStart.minusDays(daysPerBillingCycle);
                fourthOverdueEnd = fourthOverdueStart.plusDays(daysPerBillingCycle - 1);

            }
            if (deviceRentalRecordPo.getOrderExtensionInfo().getAccountPeriod().equals(1)) {
                accountPeriodIntervalMap.put(CommonConstants.UNEXPIRED_PERIOD, null);
                if (!LocalDate.now().isBefore(unexpiredPeriodStart) && !LocalDate.now().isAfter(unexpiredPeriodStart.plusDays(gracePeriod))) {
                    accountPeriodIntervalMap.put(CommonConstants.CURRENT_PERIOD, new DailyInvoiceGenerationJobDto.PeriodInterval(unexpiredPeriodStart, unexpiredPeriodEnd, new ReceivableInventoryOverdueRule.Rule("到期", "CURRENT", 50, null, null)));
                    accountPeriodIntervalMap.put("逾期0-30天", new DailyInvoiceGenerationJobDto.PeriodInterval(prevPeriodStart, prevPeriodEnd, new ReceivableInventoryOverdueRule.Rule("逾期0-30天", "OVERDUE_0_30", 40, 0, 30)));
                    accountPeriodIntervalMap.put("逾期31-60天", new DailyInvoiceGenerationJobDto.PeriodInterval(firstOverdueStart, firstOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期31-60天", "OVERDUE_31_60", 30, 31, 60)));
                    accountPeriodIntervalMap.put("逾期61-90天", new DailyInvoiceGenerationJobDto.PeriodInterval(secondOverdueStart, secondOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期61-90天", "OVERDUE_61_90", 20, 61, 90)));
                    accountPeriodIntervalMap.put("逾期91天以上", new DailyInvoiceGenerationJobDto.PeriodInterval(null, thirdOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期91天以上", "OVERDUE_90", 10, 91, null)));
                } else {
                    accountPeriodIntervalMap.put(CommonConstants.CURRENT_PERIOD, null);
                    accountPeriodIntervalMap.put("逾期0-30天", new DailyInvoiceGenerationJobDto.PeriodInterval(unexpiredPeriodStart, unexpiredPeriodEnd, new ReceivableInventoryOverdueRule.Rule("逾期0-30天", "OVERDUE_0_30", 40, 0, 30)));
                    accountPeriodIntervalMap.put("逾期31-60天", new DailyInvoiceGenerationJobDto.PeriodInterval(prevPeriodStart, prevPeriodEnd, new ReceivableInventoryOverdueRule.Rule("逾期31-60天", "OVERDUE_31_60", 30, 31, 60)));
                    accountPeriodIntervalMap.put("逾期61-90天", new DailyInvoiceGenerationJobDto.PeriodInterval(firstOverdueStart, firstOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期61-90天", "OVERDUE_61_90", 20, 61, 90)));
                    accountPeriodIntervalMap.put("逾期91天以上", new DailyInvoiceGenerationJobDto.PeriodInterval(null, secondOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期91天以上", "OVERDUE_90", 10, 91, null)));
                }
            } else {
                //每个账期区间都是一整月，当前日期所在的月份均属于未到期
                accountPeriodIntervalMap.put(CommonConstants.UNEXPIRED_PERIOD, new DailyInvoiceGenerationJobDto.PeriodInterval(unexpiredPeriodStart, unexpiredPeriodEnd, new ReceivableInventoryOverdueRule.Rule("未到期", "UNEXPIRED", 90, null, null)));
                if (!LocalDate.now().isBefore(unexpiredPeriodStart) && !LocalDate.now().isAfter(unexpiredPeriodStart.plusDays(gracePeriod))) {
                    accountPeriodIntervalMap.put(CommonConstants.CURRENT_PERIOD, new DailyInvoiceGenerationJobDto.PeriodInterval(prevPeriodStart, prevPeriodEnd, new ReceivableInventoryOverdueRule.Rule("到期", "CURRENT", 50, null, null)));
                    accountPeriodIntervalMap.put("逾期0-30天", new DailyInvoiceGenerationJobDto.PeriodInterval(firstOverdueStart, firstOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期0-30天", "OVERDUE_0_30", 40, 0, 30)));
                    accountPeriodIntervalMap.put("逾期31-60天", new DailyInvoiceGenerationJobDto.PeriodInterval(secondOverdueStart, secondOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期31-60天", "OVERDUE_31_60", 30, 31, 60)));
                    accountPeriodIntervalMap.put("逾期61-90天", new DailyInvoiceGenerationJobDto.PeriodInterval(thirdOverdueStart, thirdOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期61-90天", "OVERDUE_61_90", 20, 61, 90)));
                    accountPeriodIntervalMap.put("逾期91天以上", new DailyInvoiceGenerationJobDto.PeriodInterval(null, fourthOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期91天以上", "OVERDUE_90", 10, 91, null)));
                } else {
                    accountPeriodIntervalMap.put(CommonConstants.CURRENT_PERIOD, null);
                    accountPeriodIntervalMap.put("逾期0-30天", new DailyInvoiceGenerationJobDto.PeriodInterval(prevPeriodStart, prevPeriodEnd, new ReceivableInventoryOverdueRule.Rule("逾期0-30天", "OVERDUE_0_30", 40, 0, 30)));
                    accountPeriodIntervalMap.put("逾期31-60天", new DailyInvoiceGenerationJobDto.PeriodInterval(firstOverdueStart, firstOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期31-60天", "OVERDUE_31_60", 30, 31, 60)));
                    accountPeriodIntervalMap.put("逾期61-90天", new DailyInvoiceGenerationJobDto.PeriodInterval(secondOverdueStart, secondOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期61-90天", "OVERDUE_61_90", 20, 61, 90)));
                    accountPeriodIntervalMap.put("逾期91天以上", new DailyInvoiceGenerationJobDto.PeriodInterval(null, thirdOverdueEnd, new ReceivableInventoryOverdueRule.Rule("逾期91天以上", "OVERDUE_90", 10, 91, null)));
                }
            }
            List<OverdueDetailJson> overdueDetailList = new ArrayList<>();
            //遍历accountPeriodIntervalMap的entry
            accountPeriodIntervalMap.forEach((key, value) -> {
                //逾期账期
                OverdueDetailJson overdueDetailDto = new OverdueDetailJson();
                overdueDetailDto.setOverdueDaysDesc(key);
                if (value != null) {
                    if (value.getOverdueRule() != null) {
                        overdueDetailDto.setOverdueDaysStart(value.getOverdueRule().getStartDays());
                        overdueDetailDto.setOverdueDaysEnd(value.getOverdueRule().getEndDays());
                        overdueDetailDto.setOverdueStartDate(value.getStart());
                        overdueDetailDto.setOverdueEndDate(value.getEnd());
                    }
                    //根据value中的start和end 查询当前设备ID所有费用信息（月租价格、日租价格、总损益）
                    LambdaQueryWrapper<DeviceDailyBillPo> dailyBillPoLambdaQueryWrapper = Wrappers.lambdaQuery(DeviceDailyBillPo.class).eq(DeviceDailyBillPo::getDeviceRentalRecordId, deviceRentalRecordPo.getId()).eq(DeviceDailyBillPo::getFeeStatus, true);
                    if (value.getStart() != null) {
                        dailyBillPoLambdaQueryWrapper.ge(DeviceDailyBillPo::getFeeIncurredTime, value.getStart().atStartOfDay());
                    }
                    if (value.getEnd() != null) {
                        dailyBillPoLambdaQueryWrapper.le(DeviceDailyBillPo::getFeeIncurredTime, value.getEnd().atTime(LocalTime.MAX));
                    }
                    List<DeviceDailyBillPo> effectiveBillList = deviceDailyBillService.list(dailyBillPoLambdaQueryWrapper);
                    BigDecimal overdueAmount = effectiveBillList.stream().map(DeviceDailyBillPo::getUnpaidAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

                    //判断设备租赁记录是否已使用月租单价
                    overdueDetailDto.setOverdueAmount(overdueAmount);

                } else {
                    overdueDetailDto.setOverdueAmount(BigDecimal.ZERO);
                }
                overdueDetailList.add(overdueDetailDto);
                deviceRentalRecordPo.setOverdueInfoList(overdueDetailList);
            });

        });
        deviceRentalRecordService.updateBatchById(rentingRecordList);
        log.info("[处理时间:{}]-[合同编号:{}]-开始处理应收盘点", DateUtil.now(), contractId);
        ReceivableInventoryPo receivableInventoryPo = this.receivableInventoryMapper.selectOne(new LambdaQueryWrapper<ReceivableInventoryPo>().eq(ReceivableInventoryPo::getContractId, contractId));
        log.info("[处理时间:{}]-[合同编号:{}]-查询应收盘点结果:{}", DateUtil.now(), contractId, receivableInventoryPo);
        if (Objects.isNull(receivableInventoryPo)) {
            log.info("[处理时间:{}]-[合同编号:{}]-未查询到应收盘点,开始创建应收盘点", DateUtil.now(), contractId);
            //创建应收盘点
            return;
        }
        //设置总营收等数据
        receivableInventoryPo.setTotalRevenueAmount(rentingRecordList.stream().map(DeviceRentalRecordPo::getTotalRevenueAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        //设置TotalReconciliationedAmount需取dto.getContractDailyBillPo()中的TotalReconciliationedAmount与HistoryReconciledAmount的最大值
        receivableInventoryPo.setTotalReconciliationedAmount(rentingRecordList.stream().map(DeviceRentalRecordPo::getTotalReconciledAmount).reduce(BigDecimal.ZERO, BigDecimal::add).max(rentingRecordList.stream().map(DeviceRentalRecordPo::getHistoryReconciledAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
        //设置TotalUnreconciliationAmount=TotalRevenueAmount-TotalReconciliationedAmount
        receivableInventoryPo.setTotalUnreconciliationAmount(receivableInventoryPo.getTotalRevenueAmount().subtract(receivableInventoryPo.getTotalReconciliationedAmount()));
        //应收总额=总营收-总已收
        receivableInventoryPo.setTotalReceivableAmount(receivableInventoryPo.getTotalRevenueAmount().subtract(receivableInventoryPo.getTotalReceivedAmount()));
        //查询本合同下的所有设备的日流水数据
        //遍历dto的设备租赁记录，基于设备租赁记录中的账龄信息统计出应收盘点的逾期信息
        receivableInventoryPo.setCurrentAmount(BigDecimal.ZERO);
        receivableInventoryPo.setUnexpiredAmount(BigDecimal.ZERO);
        receivableInventoryPo.setTotalOverdueAmount(BigDecimal.ZERO);
        List<OverdueDetailJson> inventoryOverdueList = new ArrayList<>();
        //已生效的应收调整记录ID
        List<Long> profitLossRecordIds = new ArrayList<>();
        rentingRecordList.forEach(deviceRentalRecordPo -> {
            //计算设备租赁记录的账期金额
            deviceRentalRecordPo.getOverdueInfoList().forEach(item -> {
                //查询费用发生日在item.getOverdueDaysStart()和item.getOverdueDaysEnd()之间的ProfitLossRecordPo中的应收调整业务类型的记录
                //如果dto.getHandleDate等于今天
                BigDecimal adjustAmount = BigDecimal.ZERO;
                //如果item.getOverdueEndDate()不为Null
                if (item.getOverdueEndDate() != null) {
                    //计算出时间区间
                    List<ProfitLossRecordPo> profitLossRecordList = profitLossRecordService.list(Wrappers.<ProfitLossRecordPo>lambdaQuery().eq(ProfitLossRecordPo::getContractId, contractId).eq(ProfitLossRecordPo::getBusinessBillType, BusinessBillTypeEnum.RECEIVABLE_ADJUSTMENT).ge(item.getOverdueStartDate() != null, ProfitLossRecordPo::getFeeIncurredTime, item.getOverdueStartDate() != null ? item.getOverdueStartDate().atStartOfDay() : null).le(item.getOverdueEndDate() != null, ProfitLossRecordPo::getFeeIncurredTime, item.getOverdueEndDate() != null ? item.getOverdueEndDate().atTime(LocalTime.MAX) : null).eq(ProfitLossRecordPo::getIsDeleted, CommonConstants.NOT_DELETED));
                    if (CollectionUtil.isNotEmpty(profitLossRecordList)) {
                        //遍历profitLossRecordList，如果FeeType是减免类型，则减去，否则加上
                        adjustAmount = profitLossRecordList.stream().map(i -> {
                            if (profitLossRecordIds.contains(i.getId())) {
                                return BigDecimal.ZERO;
                            }
                            profitLossRecordIds.add(i.getId());
                            if (Arrays.asList(FeeTypeEnum.RENT_FEE_WAIVER, FeeTypeEnum.PAUSE_FEE_WAIVER, FeeTypeEnum.SHIPPING_FEE_WAIVER, FeeTypeEnum.MODIFICATION_FEE_WAIVER, FeeTypeEnum.CLAIMS_FEE_WAIVER).contains(i.getFeeType())) {
                                return i.getTotalFeeAmount().negate();
                            }
                            return i.getTotalFeeAmount();
                        }).reduce(BigDecimal.ZERO, BigDecimal::add);
                    }

                }


                BigDecimal overdueAmount = item.getOverdueAmount().add(adjustAmount);
                //如果item.getOverdueDaysDesc()==CommonConstants.UNEXPIRED_PERIOD,则将item.getOverdueAmount()加到receivableInventoryPo.getUnexpiredAmount()上
                //如果item.getOverdueDaysDesc()==CommonConstants.CURRENT_PERIOD,则将item.getOverdueAmount()加到receivableInventoryPo.getCurrentAmount()上
                //否则，判断inventoryOverdueList中是否存在overdueDaysDesc==item.getOverdueDaysDesc()的记录，如果存在则将item.getOverdueAmount()加到该记录的overdueAmount上，否则新增一条记录
                if (CommonConstants.UNEXPIRED_PERIOD.equals(item.getOverdueDaysDesc())) {
                    receivableInventoryPo.setUnexpiredAmount(receivableInventoryPo.getUnexpiredAmount().add(overdueAmount));
                } else if (CommonConstants.CURRENT_PERIOD.equals(item.getOverdueDaysDesc())) {
                    receivableInventoryPo.setCurrentAmount(receivableInventoryPo.getCurrentAmount().add(overdueAmount));
                } else {
                    AtomicReference<OverdueDetailJson> overdueDetailJson = new AtomicReference<>(null);
                    for (OverdueDetailJson i : inventoryOverdueList) {
                        if (i.getOverdueDaysDesc().equals(item.getOverdueDaysDesc())) {
                            overdueDetailJson.set(i);
                        }
                    }
                    if (Objects.isNull(overdueDetailJson.get())) {
                        overdueDetailJson.set(new OverdueDetailJson());
                        overdueDetailJson.get().setOverdueDaysDesc(item.getOverdueDaysDesc());
                        overdueDetailJson.get().setOverdueDaysStart(item.getOverdueDaysStart());
                        overdueDetailJson.get().setOverdueDaysEnd(item.getOverdueDaysEnd());
                        overdueDetailJson.get().setOverdueAmount(overdueAmount);
                        inventoryOverdueList.add(overdueDetailJson.get());
                    } else {
                        overdueDetailJson.get().setOverdueAmount(overdueDetailJson.get().getOverdueAmount().add(item.getOverdueAmount()));
                    }
                    receivableInventoryPo.setTotalOverdueAmount(receivableInventoryPo.getTotalOverdueAmount().add(overdueAmount));
                }
            });
            receivableInventoryPo.setOverdueDetail(inventoryOverdueList);
        });
        int result = receivableInventoryMapper.updateById(receivableInventoryPo);
        log.info("[处理时间:{}]-结束处理生成每日费用流水", DateUtil.now());
    }

    public static void main(String[] args) {
        System.out.println(LocalDate.parse("2024-05-30"));
    }
}
